package module.modbus.tcp;

import common.Const;
import common.MonitorHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import util.ByteUtil;
import util.HexFormat;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

/**
 * @author bingo
 * @Description
 * @Date 2018/8/11
 */
public class ModbusTcp {

    private Socket socket;

    private OutputStream outputStream;

    private InputStream inputStream;

    private Logger logger = LoggerFactory.getLogger(ModbusTcp.class);

    public  ModbusTcp(String ip,int port) throws IOException {

            socket = new Socket(ip,port);

    }
    public  ModbusTcp() throws IOException {
       this("127.0.0.1",502);
    }

    /***
     *   基于Tcp/ip协议数据的发送
     *   @param value  具体发送的数据
     *   @param slaveId 主机号
     *   @param  methodCode 方法码
     *   @param  startOffset 起始地址
     * */
    public  void send(int slaveId, int methodCode, int startOffset, short[] value){

        String sendData = "";
        if(methodCode== Const.READ&&value.length==1){
           sendData = read(slaveId,methodCode,startOffset,value[0]);

        }else if(methodCode==Const.SINGLE_WRITE&&value.length==1){
            sendData = write(slaveId,methodCode,startOffset,value[0]);

        }else if(methodCode==Const.MULTI_WRITE&&value.length>=1){
            sendData =   write(slaveId,methodCode,startOffset,value);

        }else {
             logger.info("数据未发送~~,功能码没找到,请查看数据格式是否正确");
             return;
        }
        //十六进制字符串转换为字节数组
        byte[] bys = ByteUtil.hexStr2Byte(sendData);
        try {
            outputStream =  socket.getOutputStream();
            outputStream.write(bys);
            outputStream.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(outputStream!=null){

            }
        }
        logger.info("TCP/ip数据发送内容:{}",sendData);
        MonitorHelper.pause(2000);
        receive();

    }


    /**接受返回的数据*/
    public  void receive(){
        try {
            inputStream  = socket.getInputStream();
           BufferedInputStream bis  = new BufferedInputStream(socket.getInputStream());
            int length = bis.available();
            byte[] bys = null;
            while (length!=0){
                bys = new byte[length];
                bis.read(bys);
                length = bis.available();
            }
            String msg = ByteUtil.byteArrayToHexString(bys);
            logger.info("收到的信息:{},长度{}",msg,msg.length());
            int methodCode = Integer.parseInt(msg.substring(14,16),16);
            if(methodCode==Const.READ){
                int len = Integer.parseInt(msg.substring(16,18),16)/2;
                for(int i=0;i<len;i++){
                    int beginInex = 18+4*i;
                    String item = msg.substring(beginInex,beginInex+4);
                    logger.info("item：{}",item);

                }
            }else if(methodCode==Const.SINGLE_WRITE||methodCode==Const.MULTI_WRITE){
                logger.info("写数据请求~~~");
            }else if(methodCode>=128){
                logger.info("数据错误~~~~~");
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }




    /**
     *  此方法对应16号功能码，写多个数据
     * */
    private String  write(int slaveId, int methodCode, int startOffset, short[] value){
        StringBuffer stringBuffer = new StringBuffer(Const.TCP_SEND_PREFIX);
        int  N =  7+value.length*2;
        stringBuffer.append(HexFormat.formatSimpple(Integer.toHexString(N)));
        stringBuffer.append(HexFormat.formatSimpple(Integer.toHexString(slaveId)));
        stringBuffer.append(HexFormat.formatSimpple(Integer.toHexString(methodCode)));
        stringBuffer.append(HexFormat.formatHex(Integer.toHexString(startOffset)));
        stringBuffer.append(HexFormat.formatHex(Integer.toHexString(value.length)));
        stringBuffer.append(HexFormat.formatSimpple(Integer.toHexString(value.length*2)));
        for(short item:value){
            stringBuffer.append(HexFormat.formatHex(Integer.toHexString(item)));
        }
        return  stringBuffer.toString();

    }
    /**
     *  此方法对应6号功能码，写单个数据
     * */
    private String  write(int slaveId, int methodCode, int startOffset, short value){
        return  splicingData(slaveId,methodCode,startOffset,value);

    }
    /**
     *  此方法对应3号功能码，读数据
     *
     * */
    private String read(int slaveId, int methodCode, int startOffset, short value){

        return  splicingData(slaveId,methodCode,startOffset,value);
    }

    /**
     *   拼接读以及单个写数据
     *
     * */
    private String  splicingData(int slaveId, int methodCode, int startOffset, short value){
        int N = 6;
        StringBuffer stringBuffer = new StringBuffer(Const.TCP_SEND_PREFIX);
        stringBuffer.append(HexFormat.formatSimpple(Integer.toHexString(N)));
        stringBuffer.append(HexFormat.formatSimpple(Integer.toHexString(slaveId)));
        stringBuffer.append(HexFormat.formatSimpple(Integer.toHexString(methodCode)));
        stringBuffer.append(HexFormat.formatHex(Integer.toHexString(startOffset)));
        stringBuffer.append(HexFormat.formatHex(Integer.toHexString(value)));
        return  stringBuffer.toString();
    }

    public Socket getSocket() {
        return socket;
    }
}
